home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / POV-Ray 3.0.2 / src / SOURCE / vbuffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-18  |  43.3 KB  |  2,048 lines  |  [TEXT/MPS ]

  1. /****************************************************************************
  2. *                   vbuffer.c
  3. *
  4. *  This module implements functions that implement the vista buffer.
  5. *
  6. *  This module was written by Dieter Bayer [DB].
  7. *
  8. *  from Persistence of Vision(tm) Ray Tracer
  9. *  Copyright 1996 Persistence of Vision Team
  10. *---------------------------------------------------------------------------
  11. *  NOTICE: This source code file is provided so that users may experiment
  12. *  with enhancements to POV-Ray and to port the software to platforms other
  13. *  than those supported by the POV-Ray Team.  There are strict rules under
  14. *  which you are permitted to use this file.  The rules are in the file
  15. *  named POVLEGAL.DOC which should be distributed with this file. If
  16. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  17. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  18. *  Forum.  The latest version of POV-Ray may be found there as well.
  19. *
  20. * This program is based on the popular DKB raytracer version 2.12.
  21. * DKBTrace was originally written by David K. Buck.
  22. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  23. *
  24. *****************************************************************************/
  25.  
  26. /****************************************************************************
  27. *
  28. *  Explanation:
  29. *
  30. *    -
  31. *
  32. *  ---
  33. *
  34. *  Mar 1994 : Creation.
  35. *
  36. *****************************************************************************/
  37.  
  38. #include "frame.h"
  39. #include "vector.h"
  40. #include "povproto.h"
  41. #include "bbox.h"
  42. #include "boxes.h"
  43. #include "hfield.h"
  44. #include "lighting.h"
  45. #include "matrices.h"
  46. #include "objects.h"
  47. #include "povray.h"
  48. #include "render.h"
  49. #include "triangle.h"
  50. #include "vbuffer.h"
  51. #include "vlbuffer.h"
  52. #include "userio.h"
  53.  
  54.  
  55.  
  56. /*****************************************************************************
  57. * Local preprocessor defines
  58. ******************************************************************************/
  59.  
  60.  
  61.  
  62. /*****************************************************************************
  63. * Local typedefs
  64. ******************************************************************************/
  65.  
  66.  
  67.  
  68. /*****************************************************************************
  69. * Local variables
  70. ******************************************************************************/
  71.  
  72. static DBL Distance;
  73. static MATRIX WC2VC, WC2VCinv;
  74. static VECTOR gO, gU, gV, gW;
  75.  
  76.  
  77. /* Planes for 3d-clipping. */
  78.  
  79. static VECTOR VIEW_VX1 = {-0.8944271910, 0.0, -0.4472135955};
  80. static VECTOR VIEW_VX2 = { 0.8944271910, 0.0, -0.4472135955};
  81. static VECTOR VIEW_VY1 = {0.0, -0.8944271910, -0.4472135955};
  82. static VECTOR VIEW_VY2 = {0.0,  0.8944271910, -0.4472135955};
  83. static DBL VIEW_DX1 = 0.4472135955;
  84. static DBL VIEW_DX2 = 0.4472135955;
  85. static DBL VIEW_DY1 = 0.4472135955;
  86. static DBL VIEW_DY2 = 0.4472135955;
  87.  
  88. static PROJECT_TREE_NODE *Root_Vista;
  89.  
  90.  
  91.  
  92. /*****************************************************************************
  93. * Static functions
  94. ******************************************************************************/
  95.  
  96. static void init_view_coordinates PARAMS((void));
  97.  
  98. static void project_raw_rectangle PARAMS((PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, VECTOR P4, int *visible));
  99. static void project_raw_triangle PARAMS((PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, int *visible));
  100.  
  101. static void project_bbox PARAMS((PROJECT *Project, VECTOR *P, int *visible));
  102. static void project_bounds PARAMS((PROJECT *Project, BBOX *BBox, int *visible));
  103.  
  104. static void get_perspective_projection PARAMS((OBJECT *Object, PROJECT *Project, int infinite));
  105. static void get_orthographic_projection PARAMS((OBJECT *Object, PROJECT *Project, int infinite));
  106.  
  107. static void project_object PARAMS((OBJECT *Object, PROJECT *Project));
  108.  
  109. static void project_box PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
  110. static void project_hfield PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
  111. static void project_triangle PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
  112. static void project_smooth_triangle PARAMS((PROJECT *Project, OBJECT *Object, int *visible));
  113.  
  114. static void transform_point PARAMS((VECTOR P));
  115.  
  116. static void project_bounding_slab PARAMS((PROJECT *Project, PROJECT_TREE_NODE **Tree, BBOX_TREE *Node));
  117.  
  118. static int intersect_vista_tree PARAMS((RAY *Ray, PROJECT_TREE_NODE *Tree, int x, INTERSECTION *Best_Intersection));
  119.  
  120. static void draw_projection PARAMS((PROJECT *Project, int color, int *BigRed, int *BigBlue));
  121. static void draw_vista PARAMS((PROJECT_TREE_NODE *Tree, int *BigRed, int *BigBlue));
  122.  
  123. static void POV_Std_Display_Plot_Box PARAMS((int x1,int y1,int x2,int y2,
  124.  unsigned int r,unsigned int g,unsigned int b,unsigned int a));
  125.  
  126. /*****************************************************************************
  127. *
  128. * FUNCTION
  129. *
  130. *   Prune_Vista_Tree
  131. *
  132. * INPUT
  133. *
  134. *   y - Current scanline number
  135. *   
  136. * OUTPUT
  137. *   
  138. * RETURNS
  139. *   
  140. * AUTHOR
  141. *
  142. *   Dieter Bayer
  143. *   
  144. * DESCRIPTION
  145. *
  146. *   Prune vista tree, i.e. mark all nodes not on the current line inactive.
  147. *
  148. * CHANGES
  149. *
  150. *   May 1994 : Creation.
  151. *
  152. ******************************************************************************/
  153.  
  154. void Prune_Vista_Tree(y)
  155. int y;
  156. {
  157.   unsigned short i;
  158.   PROJECT_TREE_NODE *Node, *Sib;
  159.  
  160.   /* If there's no vista tree then return. */
  161.  
  162.   if (Root_Vista == NULL)
  163.   {
  164.     return;
  165.   }
  166.  
  167.   Node_Queue->QSize = 0;
  168.  
  169.   Increase_Counter(stats[VBuffer_Tests]);
  170.  
  171.   if ((y < Root_Vista->Project.y1) || (y > Root_Vista->Project.y2))
  172.   {
  173.     /* Root doesn't lie on current line --> prune root */
  174.  
  175.     Root_Vista->is_leaf |= PRUNE_TEMPORARY;
  176.   }
  177.   else
  178.   {
  179.     /* Root lies on current line --> unprune root */
  180.  
  181.     Increase_Counter(stats[VBuffer_Tests_Succeeded]);
  182.  
  183.     Root_Vista->is_leaf &= ~PRUNE_TEMPORARY;
  184.  
  185.     Node_Queue->Queue[(Node_Queue->QSize)++] = Root_Vista;
  186.   }
  187.  
  188.   while (Node_Queue->QSize > 0)
  189.   {
  190.     Node = Node_Queue->Queue[--(Node_Queue->QSize)];
  191.  
  192.     if (Node->is_leaf & TRUE)
  193.     {
  194.       Increase_Counter(stats[VBuffer_Tests]);
  195.  
  196.       if ((y < Node->Project.y1) || (y > Node->Project.y2))
  197.       {
  198.         /* Leaf doesn't lie on current line --> prune leaf */
  199.  
  200.         Node->is_leaf |= PRUNE_TEMPORARY;
  201.       }
  202.       else
  203.       {
  204.         /* Leaf lies on current line --> unprune leaf */
  205.  
  206.         Increase_Counter(stats[VBuffer_Tests_Succeeded]);
  207.  
  208.         Node->is_leaf &= ~PRUNE_TEMPORARY;
  209.       }
  210.     }
  211.     else
  212.     {
  213.       /* Check siblings of the node */
  214.  
  215.       for (i = 0; i < Node->Entries; i++)
  216.       {
  217.         Sib = Node->Entry[i];
  218.  
  219.         Increase_Counter(stats[VBuffer_Tests]);
  220.  
  221.         if ((y < Sib->Project.y1) || (y > Sib->Project.y2))
  222.         {
  223.           /* Sibling doesn't lie on current line --> prune sibling */
  224.  
  225.           Sib->is_leaf |= PRUNE_TEMPORARY;
  226.         }
  227.         else
  228.         {
  229.           /* Sibling lies on current line --> unprune sibling */
  230.  
  231.           Increase_Counter(stats[VBuffer_Tests_Succeeded]);
  232.  
  233.           Sib->is_leaf &= ~PRUNE_TEMPORARY;
  234.  
  235.           /* Add sibling to list */
  236.  
  237.           /* Reallocate queue if it's too small. */
  238.           
  239.           Reinitialize_VLBuffer_Code();
  240.  
  241.           Node_Queue->Queue[(Node_Queue->QSize)++] = Sib;
  242.         }
  243.       }
  244.     }
  245.   }
  246. }
  247.  
  248.  
  249.  
  250. /*****************************************************************************
  251. *
  252. * FUNCTION
  253. *
  254. *   Trace_Primary_Ray
  255. *
  256. * INPUT
  257. *
  258. *   Ray    - Current ray
  259. *   Colour - Ray's colour
  260. *   x      - Current x-coordinate
  261. *   
  262. * OUTPUT
  263. *
  264. *   colour
  265. *   
  266. * RETURNS
  267. *   
  268. * AUTHOR
  269. *
  270. *   Dieter Bayer
  271. *   
  272. * DESCRIPTION
  273. *
  274. *   Trace a primary ray using the vista tree.
  275. *
  276. * CHANGES
  277. *
  278. *   May 1994 : Creation.
  279. *
  280. *   Nov 1994 : Rearranged calls to Fog, Ranibow and Skyblend.
  281. *              Added call to Atmosphere for atmospheric effects. [DB]
  282. *
  283. *   Jan 1995 : Set intersection depth to Max_Distance for infinte rays. [DB]
  284. *   Jul 1995 : Added code to support alpha channel. [DB]
  285. *
  286. ******************************************************************************/
  287.  
  288. void Trace_Primary_Ray (Ray, Colour, Weight, x)
  289. RAY *Ray;
  290. COLOUR Colour;
  291. DBL Weight;
  292. int x;
  293. {
  294.   int i, Intersection_Found, all_hollow;
  295.   INTERSECTION Best_Intersection;
  296.  
  297.   COOPERATE_0
  298.   Increase_Counter(stats[Number_Of_Rays]);
  299.  
  300.   /* Transmittance has to be 1 to make alpha channel output to work. [DB] */
  301.  
  302.   Make_ColourA(Colour, 0.0, 0.0, 0.0, 0.0, 1.0);
  303.  
  304.   if ((Trace_Level > Max_Trace_Level) || (Weight < ADC_Bailout))
  305.   {
  306.     if (Weight < ADC_Bailout)
  307.     {
  308.       Increase_Counter(stats[ADC_Saves]);
  309.     }
  310.  
  311.     return;
  312.   }
  313.  
  314.   if (Trace_Level > Highest_Trace_Level)
  315.   {
  316.     Highest_Trace_Level = Trace_Level;
  317.   }
  318.  
  319.   Best_Intersection.Depth = BOUND_HUGE;
  320.  
  321.   /* What objects does this ray intersect? */
  322.  
  323.   Intersection_Found = intersect_vista_tree(Ray, Root_Vista, x, &Best_Intersection);
  324.  
  325.   if (Intersection_Found)
  326.   {
  327.     Determine_Apparent_Colour(&Best_Intersection, Colour, Ray, 1.0);
  328.   }
  329.   else
  330.   {
  331.       /* Infinite ray, set intersection distance. */
  332.  
  333.       Best_Intersection.Depth = Max_Distance;
  334.  
  335.       Do_Infinite_Atmosphere(Ray, Colour);
  336.   }
  337.  
  338.   /* Test if all contained objects are hollow. */
  339.  
  340.   all_hollow = TRUE;
  341.  
  342.   if (Ray->Containing_Index > -1)
  343.   {
  344.     for (i = 0; i <= Ray->Containing_Index; i++)
  345.     {
  346.       if (!Test_Flag(Ray->Containing_Objects[i], HOLLOW_FLAG))
  347.       {
  348.         all_hollow = FALSE;
  349.  
  350.         break;
  351.       }
  352.     }
  353.   }
  354.  
  355.   /* Apply finite atmospheric effects. */
  356.  
  357.   if (all_hollow)
  358.   {
  359.     Do_Finite_Atmosphere(Ray, &Best_Intersection, Colour, FALSE);
  360.   }
  361. }
  362.  
  363.  
  364.  
  365. /*****************************************************************************
  366. *
  367. * FUNCTION
  368. *
  369. *   intersect_vista_tree
  370. *
  371. * INPUT
  372. *
  373. *   Ray               - Primary ray
  374. *   Tree              - Vista tree's top-node
  375. *   x                 - Current x-coordinate
  376. *   Best_Intersection - Intersection found
  377. *   
  378. * OUTPUT
  379. *
  380. *   Best_Intersection
  381. *   
  382. * RETURNS
  383. *   
  384. * AUTHOR
  385. *
  386. *   Dieter Bayer
  387. *   
  388. * DESCRIPTION
  389. *
  390. *   Intersect a PRIMARY ray with the vista tree
  391. *   (tree pruning is used can be primary ray!!!).
  392. *
  393. * CHANGES
  394. *
  395. *   May 1994 : Creation.
  396. *
  397. ******************************************************************************/
  398.  
  399. static int intersect_vista_tree(Ray, Tree, x, Best_Intersection)
  400. RAY *Ray;
  401. PROJECT_TREE_NODE *Tree;
  402. int x;
  403. INTERSECTION *Best_Intersection;
  404. {
  405.   INTERSECTION New_Intersection;
  406.   unsigned short i;
  407.   unsigned size;
  408.   int Found;
  409.   RAYINFO rayinfo;
  410.   DBL key;
  411.   BBOX_TREE *BBox_Node;
  412.   PROJECT_TREE_NODE *Node;
  413.  
  414.   /* If there's no vista tree then return. */
  415.  
  416.   if (Tree == NULL)
  417.   {
  418.     return(FALSE);
  419.   }
  420.  
  421.   /* Start with an empty priority queue */
  422.  
  423.   VLBuffer_Queue->QSize = 0;
  424.  
  425.   Found = FALSE;
  426.  
  427. #ifdef BBOX_EXTRA_STATS
  428.   Increase_Counter(stats[totalQueueResets]);
  429. #endif
  430.  
  431.   /* Descend tree. */
  432.  
  433.   Node_Queue->QSize = 0;
  434.  
  435.   /* Create the direction vectors for this ray */
  436.  
  437.   Create_Rayinfo(Ray, &rayinfo);
  438.  
  439.   /* Fill the priority queue with all possible candidates */
  440.  
  441.   /* Check root */
  442.  
  443.   Increase_Counter(stats[VBuffer_Tests]);
  444.  
  445.   if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2))
  446.   {
  447.     Increase_Counter(stats[VBuffer_Tests_Succeeded]);
  448.  
  449.     Node_Queue->Queue[(Node_Queue->QSize)++] = Tree;
  450.   }
  451.  
  452.   while (Node_Queue->QSize > 0)
  453.   {
  454.     Tree = Node_Queue->Queue[--(Node_Queue->QSize)];
  455.  
  456.     switch (Tree->is_leaf)
  457.     {
  458.       case FALSE:
  459.  
  460.         /* Check siblings of the unpruned node in 2d */
  461.  
  462.         for (i = 0; i < Tree->Entries; i++)
  463.         {
  464.           Node = Tree->Entry[i];
  465.  
  466.           /* Check unpruned siblings only */
  467.  
  468.           if (Node->is_leaf < PRUNE_CHECK)
  469.           {
  470.             Increase_Counter(stats[VBuffer_Tests]);
  471.  
  472.             if ((x >= Node->Project.x1) && (x <= Node->Project.x2))
  473.             {
  474.               /* Add node to node queue. */
  475.  
  476.               Increase_Counter(stats[VBuffer_Tests_Succeeded]);
  477.  
  478.               /* Reallocate queue if it's too small. */
  479.  
  480.               Reinitialize_VLBuffer_Code();
  481.  
  482.               Node_Queue->Queue[(Node_Queue->QSize)++] = Node;
  483.             }
  484.           }
  485.         }
  486.  
  487.     break;
  488.  
  489.       case TRUE:
  490.  
  491.         /* Unpruned leaf --> test object's bounding box in 3d */
  492.  
  493.         Check_And_Enqueue(VLBuffer_Queue,
  494.           ((PROJECT_TREE_LEAF *)Tree)->Node,
  495.           &(((PROJECT_TREE_LEAF *)Tree)->Node->BBox),
  496.           &rayinfo);
  497.  
  498.         break;
  499.  
  500.    /* default:
  501.  
  502.         The node/leaf is pruned and needn't be checked */
  503.  
  504.     }
  505.   }
  506.  
  507.   /* Now test the candidates in the priority queue */
  508.  
  509.   while (VLBuffer_Queue->QSize > 0)
  510.   {
  511.     Priority_Queue_Delete(VLBuffer_Queue, &key, &BBox_Node);
  512.  
  513.     if (key > Best_Intersection->Depth)
  514.       break;
  515.  
  516.     if (Intersection(&New_Intersection, (OBJECT *)BBox_Node->Node, Ray))
  517.     {
  518.       if (New_Intersection.Depth < Best_Intersection->Depth)
  519.       {
  520.         *Best_Intersection = New_Intersection;
  521.         Found = TRUE;
  522.       }
  523.     }
  524.   }
  525.  
  526.   return(Found);
  527. }
  528.  
  529.  
  530.  
  531. /*****************************************************************************
  532. *
  533. * FUNCTION
  534. *
  535. *   project_raw_triangle
  536. *
  537. * INPUT
  538. *
  539. *   Project    - Triangle's projection
  540. *   P1, P2, P3 - Triangle's edges
  541. *   visible    - Flag if triangle is visible
  542. *   
  543. * OUTPUT
  544. *
  545. *   Project, visible
  546. *   
  547. * RETURNS
  548. *   
  549. * AUTHOR
  550. *
  551. *   Dieter Bayer
  552. *   
  553. * DESCRIPTION
  554. *
  555. *   Project a triangle onto the screen.
  556. *
  557. * CHANGES
  558. *
  559. *   May 1994 : Creation.
  560. *
  561. ******************************************************************************/
  562.  
  563. static void project_raw_triangle (Project, P1, P2, P3, visible)
  564. PROJECT *Project;
  565. VECTOR P1, P2, P3;
  566. int *visible;
  567. {
  568.   VECTOR Points[MAX_CLIP_POINTS];
  569.   int i, number;
  570.   int x, y;
  571.  
  572.   Assign_Vector(Points[0], P1);
  573.   Assign_Vector(Points[1], P2);
  574.   Assign_Vector(Points[2], P3);
  575.  
  576.   number = 3;
  577.  
  578.   /* Clip triangle only if some quick tests say it's necessary.
  579.      Assuming that only a few triangles need clipping this saves some time.
  580.      (I don't need to write fabs(1+P?[Z]) since the tests succeed anyway if
  581.       P?[Z] < -1. Hope the compiler doesn't change the tests' order!) */
  582.  
  583.   if ((P1[Z] < -1.0) || (P2[Z] < -1.0) || (P3[Z] < -1.0) ||
  584.       (fabs(P1[X]) > 0.5*(1.0+P1[Z])) || (fabs(P1[Y]) > 0.5*(1.0+P1[Z])) ||
  585.       (fabs(P2[X]) > 0.5*(1.0+P2[Z])) || (fabs(P2[Y]) > 0.5*(1.0+P2[Z])) ||
  586.       (fabs(P3[X]) > 0.5*(1.0+P3[Z])) || (fabs(P3[Y]) > 0.5*(1.0+P3[Z])))
  587.   {
  588.     Clip_Polygon(Points, &number, VIEW_VX1, VIEW_VX2, VIEW_VY1, VIEW_VY2,
  589.                                   VIEW_DX1, VIEW_DX2, VIEW_DY1, VIEW_DY2);
  590.   }
  591.  
  592.   if (number)
  593.   {
  594.     for (i = 0; i < number; i++)
  595.     {
  596.       if (Points[i][Z] < -1.0 + EPSILON)
  597.       {
  598.         Points[i][X] = Points[i][Y] = 0.0;
  599.       }
  600.       else
  601.       {
  602.         Points[i][X] /= 1.0 + Points[i][Z];
  603.         Points[i][Y] /= 1.0 + Points[i][Z];
  604.       }
  605.  
  606.       x = Frame.Screen_Width/2  + (int)(Frame.Screen_Width  * Points[i][X]);
  607.       y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * Points[i][Y]);
  608.  
  609.       if (x < Project->x1) Project->x1 = x;
  610.       if (x > Project->x2) Project->x2 = x;
  611.       if (y < Project->y1) Project->y1 = y;
  612.       if (y > Project->y2) Project->y2 = y;
  613.     }
  614.  
  615.     *visible = TRUE;
  616.   }
  617. }
  618.  
  619.  
  620.  
  621. /*****************************************************************************
  622. *
  623. * FUNCTION
  624. *
  625. *   project_raw_rectangle
  626. *
  627. * INPUT
  628. *
  629. *   Project        - Rectangle's projection
  630. *   P1, P2, P3, P4 - Rectangle's edges
  631. *   visible        - Flag if rectangle is visible
  632. *   
  633. * OUTPUT
  634. *
  635. *   Project, visible
  636. *   
  637. * RETURNS
  638. *   
  639. * AUTHOR
  640. *
  641. *   Dieter Bayer
  642. *   
  643. * DESCRIPTION
  644. *
  645. *   Project a rectangle onto the screen.
  646. *
  647. * CHANGES
  648. *
  649. *   May 1994 : Creation.
  650. *
  651. ******************************************************************************/
  652.  
  653. static void project_raw_rectangle(Project, P1, P2, P3, P4, visible)
  654. PROJECT *Project;
  655. VECTOR P1, P2, P3, P4;
  656. int *visible;
  657. {
  658.   VECTOR Points[MAX_CLIP_POINTS];
  659.   int i, number;
  660.   int x, y;
  661.  
  662.   Assign_Vector(Points[0], P1);
  663.   Assign_Vector(Points[1], P2);
  664.   Assign_Vector(Points[2], P3);
  665.   Assign_Vector(Points[3], P4);
  666.  
  667.   number = 4;
  668.  
  669.   Clip_Polygon(Points, &number, VIEW_VX1, VIEW_VX2, VIEW_VY1, VIEW_VY2,
  670.                                 VIEW_DX1, VIEW_DX2, VIEW_DY1, VIEW_DY2);
  671.  
  672.   if (number)
  673.   {
  674.     for (i = 0; i < number; i++)
  675.     {
  676.       if (Points[i][Z] < -1.0 + EPSILON)
  677.       {
  678.         Points[i][X] = Points[i][Y] = 0.0;
  679.       }
  680.       else
  681.       {
  682.         Points[i][X] /= 1.0 + Points[i][Z];
  683.         Points[i][Y] /= 1.0 + Points[i][Z];
  684.       }
  685.  
  686.       x = Frame.Screen_Width/2  + (int)(Frame.Screen_Width  * Points[i][X]);
  687.       y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * Points[i][Y]);
  688.  
  689.       if (x < Project->x1) Project->x1 = x;
  690.       if (x > Project->x2) Project->x2 = x;
  691.       if (y < Project->y1) Project->y1 = y;
  692.       if (y > Project->y2) Project->y2 = y;
  693.     }
  694.  
  695.     *visible = TRUE;
  696.   }
  697. }
  698.  
  699.  
  700.  
  701.  
  702. /*****************************************************************************
  703. *
  704. * FUNCTION
  705. *
  706. *   project_bbox
  707. *
  708. * INPUT
  709. *
  710. *   Project - Box's projection
  711. *   P       - Box's edges
  712. *   visible - Flag if box is visible
  713. *   
  714. * OUTPUT
  715. *
  716. *   Project, visible
  717. *   
  718. * RETURNS
  719. *   
  720. * AUTHOR
  721. *
  722. *   Dieter Bayer
  723. *   
  724. * DESCRIPTION
  725. *
  726. *   Project a box onto the screen.
  727. *
  728. * CHANGES
  729. *
  730. *   May 1994 : Creation.
  731. *
  732. ******************************************************************************/
  733.  
  734. static void project_bbox(Project, P, visible)
  735. PROJECT *Project;
  736. VECTOR *P;
  737. int *visible;
  738. {
  739.   int vis, i, x, y;
  740.   PROJECT New;
  741.  
  742.   New.x1 = MAX_BUFFER_ENTRY;
  743.   New.x2 = MIN_BUFFER_ENTRY;
  744.   New.y1 = MAX_BUFFER_ENTRY;
  745.   New.y2 = MIN_BUFFER_ENTRY;
  746.  
  747.   vis = FALSE;
  748.  
  749.   /* Check if all points lie "in front" of the viewer. */
  750.  
  751.   if ((P[0][Z] > -1.0) && (P[1][Z] > -1.0) && (P[2][Z] > -1.0) && (P[3][Z] > -1.0) &&
  752.       (P[4][Z] > -1.0) && (P[5][Z] > -1.0) && (P[6][Z] > -1.0) && (P[7][Z] > -1.0))
  753.   {
  754.     /* Check if all points lie inside the "viewing pyramid". */
  755.  
  756.     if ((fabs(P[0][X]) <= 0.5*(1.0+P[0][Z])) && (fabs(P[1][X]) <= 0.5*(1.0+P[1][Z])) &&
  757.         (fabs(P[2][X]) <= 0.5*(1.0+P[2][Z])) && (fabs(P[3][X]) <= 0.5*(1.0+P[3][Z])) &&
  758.         (fabs(P[4][X]) <= 0.5*(1.0+P[4][Z])) && (fabs(P[5][X]) <= 0.5*(1.0+P[5][Z])) &&
  759.         (fabs(P[6][X]) <= 0.5*(1.0+P[6][Z])) && (fabs(P[7][X]) <= 0.5*(1.0+P[7][Z])) &&
  760.         (fabs(P[0][Y]) <= 0.5*(1.0+P[0][Z])) && (fabs(P[1][Y]) <= 0.5*(1.0+P[1][Z])) &&
  761.         (fabs(P[2][Y]) <= 0.5*(1.0+P[2][Z])) && (fabs(P[3][Y]) <= 0.5*(1.0+P[3][Z])) &&
  762.         (fabs(P[4][Y]) <= 0.5*(1.0+P[4][Z])) && (fabs(P[5][Y]) <= 0.5*(1.0+P[5][Z])) &&
  763.         (fabs(P[6][Y]) <= 0.5*(1.0+P[6][Z])) && (fabs(P[7][Y]) <= 0.5*(1.0+P[7][Z])))
  764.     {
  765.       /* No clipping is needed. Just project the points. */
  766.  
  767.       vis = TRUE;
  768.  
  769.       for (i = 0; i < 8; i++)
  770.       {
  771.         if (P[i][Z] < -1.0 + EPSILON)
  772.         {
  773.           P[i][X] = P[i][Y] = 0.0;
  774.         }
  775.         else
  776.         {
  777.           P[i][X] /= 1.0 + P[i][Z];
  778.           P[i][Y] /= 1.0 + P[i][Z];
  779.         }
  780.  
  781.         x = Frame.Screen_Width/2  + (int)(Frame.Screen_Width  * P[i][X]);
  782.         y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * P[i][Y]);
  783.  
  784.         if (x < New.x1) New.x1 = x;
  785.         if (x > New.x2) New.x2 = x;
  786.         if (y < New.y1) New.y1 = y;
  787.         if (y > New.y2) New.y2 = y;
  788.       }
  789.     }
  790.   }
  791.  
  792.   if (!vis)
  793.   {
  794.     project_raw_rectangle(&New, P[0], P[1], P[3], P[2], &vis);
  795.     project_raw_rectangle(&New, P[4], P[5], P[7], P[6], &vis);
  796.     project_raw_rectangle(&New, P[0], P[1], P[5], P[4], &vis);
  797.     project_raw_rectangle(&New, P[2], P[3], P[7], P[6], &vis);
  798.     project_raw_rectangle(&New, P[1], P[3], P[7], P[5], &vis);
  799.     project_raw_rectangle(&New, P[0], P[2], P[6], P[4], &vis);
  800.   }
  801.  
  802.   if (vis)
  803.   {
  804.     if (New.x1 > Project->x1) Project->x1 = New.x1;
  805.     if (New.x2 < Project->x2) Project->x2 = New.x2;
  806.     if (New.y1 > Project->y1) Project->y1 = New.y1;
  807.     if (New.y2 < Project->y2) Project->y2 = New.y2;
  808.     *visible = TRUE;
  809.   }
  810. }
  811.  
  812.  
  813.  
  814. /*****************************************************************************
  815. *
  816. * FUNCTION
  817. *
  818. *   project_bounds
  819. *
  820. * INPUT
  821. *
  822. *   Project - Bounding box's projection
  823. *   BBox    - Bounding box
  824. *   visible - Flag if bounding box is visible
  825. *   
  826. * OUTPUT
  827. *
  828. *   Project, visible
  829. *   
  830. * RETURNS
  831. *   
  832. * AUTHOR
  833. *
  834. *   Dieter Bayer
  835. *   
  836. * DESCRIPTION
  837. *
  838. *   Project a bounding box onto the screen.
  839. *
  840. * CHANGES
  841. *
  842. *   May 1994 : Creation.
  843. *
  844. ******************************************************************************/
  845.  
  846. static void project_bounds(Project, BBox, visible)
  847. PROJECT *Project;
  848. BBOX *BBox;
  849. int *visible;
  850. {
  851.   int i;
  852.   VECTOR P[8];
  853.  
  854.   for (i = 0; i<8; i++)
  855.   {
  856.     P[i][X] = ((i & 1) ? BBox->Lengths[X] : 0.0) + BBox->Lower_Left[X];
  857.     P[i][Y] = ((i & 2) ? BBox->Lengths[Y] : 0.0) + BBox->Lower_Left[Y];
  858.     P[i][Z] = ((i & 4) ? BBox->Lengths[Z] : 0.0) + BBox->Lower_Left[Z];
  859.  
  860.     transform_point(P[i]);
  861.   }
  862.  
  863.   project_bbox(Project, P, visible);
  864. }
  865.  
  866.  
  867.  
  868. /*****************************************************************************
  869. *
  870. * FUNCTION
  871. *
  872. *   project_box
  873. *
  874. * INPUT
  875. *
  876. *   Project - Projection
  877. *   Object  - Object
  878. *   visible - Flag if object is visible
  879. *   
  880. * OUTPUT
  881. *
  882. *   Project, visible
  883. *   
  884. * RETURNS
  885. *   
  886. * AUTHOR
  887. *
  888. *   Dieter Bayer
  889. *   
  890. * DESCRIPTION
  891. *
  892. *   Project a box onto the screen.
  893. *
  894. * CHANGES
  895. *
  896. *   May 1994 : Creation.
  897. *
  898. ******************************************************************************/
  899.  
  900. static void project_box(Project, Object, visible)
  901. PROJECT *Project;
  902. OBJECT *Object;
  903. int *visible;
  904. {
  905.   int i;
  906.   VECTOR P[8];
  907.   BOX *box;
  908.  
  909.   box = (BOX *)Object;
  910.  
  911.   for (i = 0; i<8; i++)
  912.   {
  913.     P[i][X] = (i & 1) ? box->bounds[1][X] : box->bounds[0][X];
  914.     P[i][Y] = (i & 2) ? box->bounds[1][Y] : box->bounds[0][Y];
  915.     P[i][Z] = (i & 4) ? box->bounds[1][Z] : box->bounds[0][Z];
  916.  
  917.     if (box->Trans != NULL)
  918.     {
  919.       MTransPoint(P[i], P[i], box->Trans);
  920.     }
  921.  
  922.     transform_point(P[i]);
  923.   }
  924.  
  925.   project_bbox(Project, P, visible);
  926. }
  927.  
  928.  
  929.  
  930. /*****************************************************************************
  931. *
  932. * FUNCTION
  933. *
  934. *   project_hfield
  935. *
  936. * INPUT
  937. *
  938. *   Project - Projection
  939. *   Object  - Object
  940. *   visible - Flag if object is visible
  941. *   
  942. * OUTPUT
  943. *
  944. *   Project, visible
  945. *   
  946. * RETURNS
  947. *   
  948. * AUTHOR
  949. *
  950. *   Dieter Bayer
  951. *   
  952. * DESCRIPTION
  953. *
  954. *   Project the bounding box of a height field onto the screen.
  955. *
  956. * CHANGES
  957. *
  958. *   May 1994 : Creation.
  959. *
  960. ******************************************************************************/
  961.  
  962. static void project_hfield(Project, Object, visible)
  963. PROJECT *Project;
  964. OBJECT *Object;
  965. int *visible;
  966. {
  967.   int i;
  968.   VECTOR P[8];
  969.   HFIELD *hfield;
  970.  
  971.   hfield = (HFIELD *)Object;
  972.  
  973.   for (i = 0; i<8; i++)
  974.   {
  975.     Assign_Vector(P[i], hfield->bounding_box->bounds[0]);
  976.  
  977.     P[i][X] = (i & 1) ? hfield->bounding_box->bounds[1][X] : hfield->bounding_box->bounds[0][X];
  978.     P[i][Y] = (i & 2) ? hfield->bounding_box->bounds[1][Y] : hfield->bounding_box->bounds[0][Y];
  979.     P[i][Z] = (i & 4) ? hfield->bounding_box->bounds[1][Z] : hfield->bounding_box->bounds[0][Z];
  980.  
  981.     if (hfield->Trans != NULL)
  982.     {
  983.       MTransPoint(P[i], P[i], hfield->Trans);
  984.     }
  985.  
  986.     transform_point(P[i]);
  987.   }
  988.  
  989.   project_bbox(Project, P, visible);
  990. }
  991.  
  992.  
  993.  
  994. /*****************************************************************************
  995. *
  996. * FUNCTION
  997. *
  998. *   project_triangle
  999. *
  1000. * INPUT
  1001. *
  1002. *   Project - Projection
  1003. *   Object  - Object
  1004. *   visible - Flag if object is visible
  1005. *   
  1006. * OUTPUT
  1007. *
  1008. *   Project, visible
  1009. *   
  1010. * RETURNS
  1011. *   
  1012. * AUTHOR
  1013. *
  1014. *   Dieter Bayer
  1015. *   
  1016. * DESCRIPTION
  1017. *
  1018. *   Project a triangle onto the screen.
  1019. *
  1020. * CHANGES
  1021. *
  1022. *   May 1994 : Creation.
  1023. *
  1024. ******************************************************************************/
  1025.  
  1026. static void project_triangle(Project, Object, visible)
  1027. PROJECT *Project;
  1028. OBJECT *Object;
  1029. int *visible;
  1030. {
  1031.   int i, vis;
  1032.   VECTOR P[3];
  1033.   PROJECT New;
  1034.  
  1035.   New.x1 = MAX_BUFFER_ENTRY;
  1036.   New.x2 = MIN_BUFFER_ENTRY;
  1037.   New.y1 = MAX_BUFFER_ENTRY;
  1038.   New.y2 = MIN_BUFFER_ENTRY;
  1039.  
  1040.   Assign_Vector(P[0], ((TRIANGLE *)Object)->P1);
  1041.   Assign_Vector(P[1], ((TRIANGLE *)Object)->P2);
  1042.   Assign_Vector(P[2], ((TRIANGLE *)Object)->P3);
  1043.  
  1044.   for (i = 0; i < 3; i++)
  1045.   {
  1046.     transform_point(P[i]);
  1047.   }
  1048.  
  1049.   vis = FALSE;
  1050.  
  1051.   project_raw_triangle(&New, P[0], P[1], P[2], &vis);
  1052.  
  1053.   if (vis)
  1054.   {
  1055.     if (New.x1 > Project->x1) Project->x1 = New.x1;
  1056.     if (New.x2 < Project->x2) Project->x2 = New.x2;
  1057.     if (New.y1 > Project->y1) Project->y1 = New.y1;
  1058.     if (New.y2 < Project->y2) Project->y2 = New.y2;
  1059.  
  1060.     *visible = TRUE;
  1061.   }
  1062. }
  1063.  
  1064.  
  1065.  
  1066. /*****************************************************************************
  1067. *
  1068. * FUNCTION
  1069. *
  1070. *   project_smooth_triangle
  1071. *
  1072. * INPUT
  1073. *
  1074. *   Project - Projection
  1075. *   Object  - Object
  1076. *   visible - Flag if object is visible
  1077. *   
  1078. * OUTPUT
  1079. *
  1080. *   Project, visible
  1081. *   
  1082. * RETURNS
  1083. *   
  1084. * AUTHOR
  1085. *
  1086. *   Dieter Bayer
  1087. *   
  1088. * DESCRIPTION
  1089. *
  1090. *   Project a smooth triangle onto the screen.
  1091. *
  1092. * CHANGES
  1093. *
  1094. *   May 1994 : Creation.
  1095. *
  1096. ******************************************************************************/
  1097.  
  1098. static void project_smooth_triangle(Project, Object, visible)
  1099. PROJECT *Project;
  1100. OBJECT *Object;
  1101. int *visible;
  1102. {
  1103.   int i, vis;
  1104.   VECTOR P[3];
  1105.   PROJECT New;
  1106.  
  1107.   New.x1 = MAX_BUFFER_ENTRY;
  1108.   New.x2 = MIN_BUFFER_ENTRY;
  1109.   New.y1 = MAX_BUFFER_ENTRY;
  1110.   New.y2 = MIN_BUFFER_ENTRY;
  1111.  
  1112.   Assign_Vector(P[0], ((SMOOTH_TRIANGLE *)Object)->P1);
  1113.   Assign_Vector(P[1], ((SMOOTH_TRIANGLE *)Object)->P2);
  1114.   Assign_Vector(P[2], ((SMOOTH_TRIANGLE *)Object)->P3);
  1115.  
  1116.   for (i = 0; i < 3; i++)
  1117.   {
  1118.     transform_point(P[i]);
  1119.   }
  1120.  
  1121.   vis = FALSE;
  1122.  
  1123.   project_raw_triangle(&New, P[0], P[1], P[2], &vis);
  1124.  
  1125.   if (vis)
  1126.   {
  1127.     if (New.x1 > Project->x1) Project->x1 = New.x1;
  1128.     if (New.x2 < Project->x2) Project->x2 = New.x2;
  1129.     if (New.y1 > Project->y1) Project->y1 = New.y1;
  1130.     if (New.y2 < Project->y2) Project->y2 = New.y2;
  1131.  
  1132.     *visible = TRUE;
  1133.   }
  1134. }
  1135.  
  1136.  
  1137.  
  1138. /*****************************************************************************
  1139. *
  1140. * FUNCTION
  1141. *
  1142. *   transform_point
  1143. *
  1144. * INPUT
  1145. *
  1146. *   P - Point to transform
  1147. *   
  1148. * OUTPUT
  1149. *
  1150. *   P
  1151. *   
  1152. * RETURNS
  1153. *   
  1154. * AUTHOR
  1155. *
  1156. *   Dieter Bayer
  1157. *   
  1158. * DESCRIPTION
  1159. *
  1160. *   Transform a point from the world coordinate system to the viewer's
  1161. *   coordinate system.
  1162. *
  1163. * CHANGES
  1164. *
  1165. *   May 1994 : Creation.
  1166. *
  1167. ******************************************************************************/
  1168.  
  1169. static void transform_point(P)
  1170. VECTOR P;
  1171. {
  1172.   DBL x,y,z;
  1173.  
  1174.   x = P[X] - gO[X];
  1175.   y = P[Y] - gO[Y];
  1176.   z = P[Z] - gO[Z];
  1177.  
  1178.   P[X] = gU[X] * x + gU[Y] * y + gU[Z] * z;
  1179.   P[Y] = gV[X] * x + gV[Y] * y + gV[Z] * z;
  1180.   P[Z] = gW[X] * x + gW[Y] * y + gW[Z] * z;
  1181. }
  1182.  
  1183.  
  1184.  
  1185. /*****************************************************************************
  1186. *
  1187. * FUNCTION
  1188. *
  1189. *   Init_View_Coordinates
  1190. *
  1191. * INPUT
  1192. *   
  1193. * OUTPUT
  1194. *   
  1195. * RETURNS
  1196. *   
  1197. * AUTHOR
  1198. *
  1199. *   Dieter Bayer
  1200. *   
  1201. * DESCRIPTION
  1202. *
  1203. *   Init the matrices and vectors used to transform a point from
  1204. *   the world coordinate system to the viewer's coordinate system.
  1205. *
  1206. * CHANGES
  1207. *
  1208. *   May 1994 : Creation.
  1209. *
  1210. ******************************************************************************/
  1211.  
  1212. static void init_view_coordinates()
  1213. {
  1214.   DBL k1, k2, k3, up_length, right_length;
  1215.   MATRIX A, B;
  1216.  
  1217.   Assign_Vector(gU, Frame.Camera->Right);
  1218.   Assign_Vector(gV, Frame.Camera->Up);
  1219.   Assign_Vector(gW, Frame.Camera->Direction);
  1220.  
  1221.   VAdd (gO, Frame.Camera->Location, Frame.Camera->Direction);
  1222.  
  1223.   VNormalize(gU,gU);
  1224.   VNormalize(gV,gV);
  1225.   VNormalize(gW,gW);
  1226.  
  1227.   VDot(k1, gU, gV);
  1228.   VDot(k2, gU, gW);
  1229.   VDot(k3, gV, gW);
  1230.  
  1231.   if ((fabs(k1) > EPSILON) || (fabs(k2) > EPSILON) || (fabs(k3) > EPSILON))
  1232.   {
  1233.     Error("Cannot use non-perpendicular camera vectors with vista buffer.\n");
  1234.   }
  1235.  
  1236.   VLength (Distance, Frame.Camera->Direction);
  1237.  
  1238.   VLength (up_length, Frame.Camera->Up);
  1239.   VLength (right_length, Frame.Camera->Right);
  1240.  
  1241.   VScaleEq (gU, 1.0/right_length);
  1242.   VScaleEq (gV, 1.0/up_length);
  1243.   VScaleEq (gW, 1.0/Distance);
  1244.  
  1245.   A[0][0] = gU[X]; A[0][1] = gU[Y]; A[0][2] = gU[Z]; A[0][3] = 0.0;
  1246.   A[1][0] = gV[X]; A[1][1] = gV[Y]; A[1][2] = gV[Z]; A[1][3] = 0.0;
  1247.   A[2][0] = gW[X]; A[2][1] = gW[Y]; A[2][2] = gW[Z]; A[2][3] = 0.0;
  1248.   A[3][0] = 0.0;  A[3][1] = 0.0;  A[3][2] = 0.0;  A[3][3] = 1.0;
  1249.  
  1250.   B[0][0] = 1.0; B[0][1] = 0.0; B[0][2] = 0.0; B[0][3] = -gO[X];
  1251.   B[1][0] = 0.0; B[1][1] = 1.0; B[1][2] = 0.0; B[1][3] = -gO[Y];
  1252.   B[2][0] = 0.0; B[2][1] = 0.0; B[2][2] = 1.0; B[2][3] = -gO[Z];
  1253.   B[3][0] = 0.0; B[3][1] = 0.0; B[3][2] = 0.0; B[3][3] = 1.0;
  1254.  
  1255.   MTimes(WC2VC, A, B);
  1256.   MInvers(WC2VCinv, WC2VC);
  1257. }
  1258.  
  1259.  
  1260.  
  1261. /*****************************************************************************
  1262. *
  1263. * FUNCTION
  1264. *
  1265. *   get_perspective_projection
  1266. *
  1267. * INPUT
  1268. *
  1269. *   Object   - Object to project
  1270. *   Project  - Projection
  1271. *   infinite - Flag if object is infinite
  1272. *   
  1273. * OUTPUT
  1274. *
  1275. *   Project
  1276. *   
  1277. * RETURNS
  1278. *   
  1279. * AUTHOR
  1280. *
  1281. *   Dieter Bayer
  1282. *   
  1283. * DESCRIPTION
  1284. *
  1285. *   Get the perspective projection of a single object, i.e.
  1286. *   the smallest rectangle enclosing the object's image on the screen.
  1287. *
  1288. * CHANGES
  1289. *
  1290. *   May 1994 : Creation.
  1291. *
  1292. ******************************************************************************/
  1293.  
  1294. static void get_perspective_projection(Object, Project, infinite)
  1295. OBJECT *Object;
  1296. PROJECT *Project;
  1297. int infinite;
  1298. {
  1299.   int visible;
  1300.   METHODS *Methods;
  1301.  
  1302.   visible = FALSE;
  1303.  
  1304.   Methods = Object->Methods;
  1305.  
  1306.   /* If the object is infinite, there's no sense of projecting */
  1307.  
  1308.   if (!infinite)
  1309.   {
  1310.     if ((Methods == &Box_Methods) ||
  1311.         (Methods == &Smooth_Triangle_Methods) ||
  1312.         (Methods == &Triangle_Methods) ||
  1313.         (Methods == &HField_Methods))
  1314.     {
  1315.       if (Methods == &Box_Methods)
  1316.         project_box(Project, Object, &visible);
  1317.  
  1318.       if (Methods == &HField_Methods)
  1319.         project_hfield(Project, Object, &visible);
  1320.  
  1321.       if (Methods == &Smooth_Triangle_Methods)
  1322.         project_smooth_triangle(Project, Object, &visible);
  1323.  
  1324.       if (Methods == &Triangle_Methods)
  1325.         project_triangle(Project, Object, &visible);
  1326.     }
  1327.     else
  1328.     {
  1329.       project_bounds(Project, &Object->BBox, &visible);
  1330.     }
  1331.   }
  1332.  
  1333.   if (visible)
  1334.   {
  1335.     if (opts.Options & ANTIALIAS)
  1336.     {
  1337.       /* Increase the rectangle to make sure that nothing will be missed.
  1338.          For anti-aliased images increase by a larger amount. */
  1339.  
  1340.       Project->x1 = max (0,                     Project->x1 - 2);
  1341.       Project->x2 = min (Frame.Screen_Width-1,  Project->x2 + 2);
  1342.       Project->y1 = max (-1,                    Project->y1 - 2);
  1343.       Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 2);
  1344.     }
  1345.     else
  1346.     {
  1347.       /* Increase the rectangle to make sure that nothing will be missed. */
  1348.  
  1349.       Project->x1 = max (0,                     Project->x1 - 1);
  1350.       Project->x2 = min (Frame.Screen_Width-1,  Project->x2 + 1);
  1351.       Project->y1 = max (0,                     Project->y1 - 1);
  1352.       Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);
  1353.     }
  1354.   }
  1355.   else
  1356.   {
  1357.     if (!infinite)
  1358.     {
  1359.       /* Object is invisible (the camera can't see it) */
  1360.  
  1361.       Project->x1 = Project->y1 = MAX_BUFFER_ENTRY;
  1362.       Project->x2 = Project->y2 = MIN_BUFFER_ENTRY;
  1363.     }
  1364.   }
  1365. }
  1366.  
  1367.  
  1368.  
  1369. /*****************************************************************************
  1370. *
  1371. * FUNCTION
  1372. *
  1373. *   get_orthographic_projection
  1374. *
  1375. * INPUT
  1376. *
  1377. *   Object   - Object to project
  1378. *   Project  - Projection
  1379. *   infinite - Flag if object is infinite
  1380. *   
  1381. * OUTPUT
  1382. *
  1383. *   Project
  1384. *   
  1385. * RETURNS
  1386. *   
  1387. * AUTHOR
  1388. *
  1389. *   Dieter Bayer
  1390. *   
  1391. * DESCRIPTION
  1392. *
  1393. *   Get the orthographic projection of a single object, i.e.
  1394. *   the smallest rectangle enclosing the object's image on the screen.
  1395. *
  1396. * CHANGES
  1397. *
  1398. *   May 1994 : Creation.
  1399. *
  1400. ******************************************************************************/
  1401.  
  1402. static void get_orthographic_projection(Object, Project, infinite)
  1403. OBJECT *Object;
  1404. PROJECT *Project;
  1405. int infinite;
  1406. {
  1407.   int visible, i, x, y;
  1408.   VECTOR P[8];
  1409.  
  1410.   visible = FALSE;
  1411.  
  1412.   /* If the object is infinite, there's no sense of projecting */
  1413.  
  1414.   if (!infinite)
  1415.   {
  1416.     /* The following could be done better but since only a minority of all
  1417.        objects in a scene are partially visible I don't think it's worth it. */
  1418.  
  1419.     for (i = 0; i < 8; i++)
  1420.     {
  1421.       P[i][X] = ((i & 1) ? Object->BBox.Lengths[X] : 0.0) + Object->BBox.Lower_Left[X];
  1422.       P[i][Y] = ((i & 2) ? Object->BBox.Lengths[Y] : 0.0) + Object->BBox.Lower_Left[Y];
  1423.       P[i][Z] = ((i & 4) ? Object->BBox.Lengths[Z] : 0.0) + Object->BBox.Lower_Left[Z];
  1424.  
  1425.       transform_point(P[i]);
  1426.  
  1427.       /* Check if bounding box is visible */
  1428.  
  1429.       if (P[i][Z] >= 0.0) visible = TRUE;
  1430.     }
  1431.  
  1432.     /* Now get the projection */
  1433.  
  1434.     if (visible)
  1435.     {
  1436.       Project->x1 = Project->y1 = MAX_BUFFER_ENTRY;
  1437.       Project->x2 = Project->y2 = MIN_BUFFER_ENTRY;
  1438.  
  1439.       for (i = 0; i < 8; i++)
  1440.       {
  1441.         /* The visible area is -0.5...+0.5/-0.5...+0.5 */
  1442.  
  1443.         if (P[i][X] < -0.5) P[i][X] = -0.5;
  1444.         if (P[i][X] >  0.5) P[i][X] =  0.5;
  1445.         if (P[i][Y] < -0.5) P[i][Y] = -0.5;
  1446.         if (P[i][Y] >  0.5) P[i][Y] =  0.5;
  1447.  
  1448.         x = Frame.Screen_Width/2  + (int)(Frame.Screen_Width  * P[i][X]);
  1449.         y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * P[i][Y]);
  1450.  
  1451.         if (x < Project->x1) Project->x1 = x;
  1452.         if (x > Project->x2) Project->x2 = x;
  1453.         if (y < Project->y1) Project->y1 = y;
  1454.         if (y > Project->y2) Project->y2 = y;
  1455.       }
  1456.     }
  1457.   }
  1458.  
  1459.   if (visible)
  1460.   {
  1461.     if (opts.Options & ANTIALIAS)
  1462.     {
  1463.       /* Increase the rectangle to make sure that nothing will be missed.
  1464.          For anti-aliased images decrease the lower borders. */
  1465.  
  1466.       Project->x1 = max (0,                     Project->x1 - 2);
  1467.       Project->x2 = min (Frame.Screen_Width-1,  Project->x2 + 1);
  1468.       Project->y1 = max (-1,                    Project->y1 - 2);
  1469.       Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);
  1470.     }
  1471.     else
  1472.     {
  1473.       /* Increase the rectangle to make sure that nothing will be missed. */
  1474.  
  1475.       Project->x1 = max (0,                     Project->x1 - 1);
  1476.       Project->x2 = min (Frame.Screen_Width-1,  Project->x2 + 1);
  1477.       Project->y1 = max (0,                     Project->y1 - 1);
  1478.       Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);
  1479.     }
  1480.   }
  1481.   else
  1482.   {
  1483.     if (!infinite)
  1484.     {
  1485.       /* Object is invisible (the camera can't see it) */
  1486.  
  1487.       Project->x1 = Project->y1 = MAX_BUFFER_ENTRY;
  1488.       Project->x2 = Project->y2 = MIN_BUFFER_ENTRY;
  1489.     }
  1490.   }
  1491. }
  1492.  
  1493.  
  1494.  
  1495. /*****************************************************************************
  1496. *
  1497. * FUNCTION
  1498. *
  1499. *   project_object
  1500. *
  1501. * INPUT
  1502. *
  1503. *   Object   - Object to project
  1504. *   Project  - Projection
  1505. *   
  1506. * OUTPUT
  1507. *
  1508. *   Project
  1509. *   
  1510. * RETURNS
  1511. *   
  1512. * AUTHOR
  1513. *
  1514. *   Dieter Bayer
  1515. *   
  1516. * DESCRIPTION
  1517. *
  1518. *   Get the projection of a single object depending on the camera
  1519. *   used (perspective/orthographic).
  1520. *
  1521. * CHANGES
  1522. *
  1523. *   May 1994 : Creation.
  1524. *
  1525. ******************************************************************************/
  1526.  
  1527. static void project_object(Object, Project)
  1528. OBJECT *Object;
  1529. PROJECT *Project;
  1530. {
  1531.   int infinite;
  1532.  
  1533.   /* Init project fields, assuming the object is visible! */
  1534.  
  1535.   Project->x1 = Project->y1 = MIN_BUFFER_ENTRY;
  1536.   Project->x2 = Project->y2 = MAX_BUFFER_ENTRY;
  1537.  
  1538.   infinite = Test_Flag(Object, INFINITE_FLAG);
  1539.  
  1540.   switch (Frame.Camera->Type)
  1541.   {
  1542.     case PERSPECTIVE_CAMERA:
  1543.  
  1544.       get_perspective_projection(Object, Project, infinite);
  1545.       break;
  1546.  
  1547.     case ORTHOGRAPHIC_CAMERA:
  1548.  
  1549.       get_orthographic_projection(Object, Project, infinite);
  1550.       break;
  1551.  
  1552.     default:
  1553.  
  1554.       Error("Wrong camera type in project_object().\n");
  1555.       break;
  1556.   }
  1557. }
  1558.  
  1559.  
  1560.  
  1561. /*****************************************************************************
  1562. *
  1563. * FUNCTION
  1564. *
  1565. *   project_bounding_slab
  1566. *
  1567. * INPUT
  1568. *
  1569. *   Project  - Projection
  1570. *   Tree     - Current node/leaf
  1571. *   Object   - Node/leaf in bounding slab hierarchy
  1572. *   
  1573. * OUTPUT
  1574. *
  1575. *   Project, Tree
  1576. *   
  1577. * RETURNS
  1578. *   
  1579. * AUTHOR
  1580. *
  1581. *   Dieter Bayer
  1582. *   
  1583. * DESCRIPTION
  1584. *
  1585. *   Project the bounding slab hierarchy onto the screen and thus create
  1586. *   the vista buffer hierarchy.
  1587. *
  1588. * CHANGES
  1589. *
  1590. *   May 1994 : Creation.
  1591. *
  1592. ******************************************************************************/
  1593.  
  1594. static void project_bounding_slab(Project, Tree, Node)
  1595. PROJECT *Project;
  1596. PROJECT_TREE_NODE **Tree;
  1597. BBOX_TREE *Node;
  1598. {
  1599.   short int i;
  1600.   PROJECT Temp;
  1601.   PROJECT_TREE_LEAF *Leaf;
  1602.   PROJECT_TREE_NODE New;
  1603.  
  1604.   if (Node->Entries)
  1605.   {
  1606.     /* Current object is a bounding object, i.e. a node in the slab tree. */
  1607.  
  1608.     /* First, init new entry. */
  1609.  
  1610.     New.Entries = 0;
  1611.  
  1612.     New.Node = Node;
  1613.  
  1614.     New.Project.x1 = New.Project.y1 = MAX_BUFFER_ENTRY;
  1615.     New.Project.x2 = New.Project.y2 = MIN_BUFFER_ENTRY;
  1616.  
  1617.     /* Allocate temporary memory for node/leaf entries. */
  1618.  
  1619.     New.Entry = (PROJECT_TREE_NODE **)POV_MALLOC(Node->Entries*sizeof(PROJECT_TREE_NODE *), "temporary tree entry");
  1620.  
  1621.     /* This is no leaf, it's a node. */
  1622.  
  1623.     New.is_leaf = FALSE;
  1624.  
  1625.     /* Second, get new entry, i.e. project node's entries. */
  1626.  
  1627.     for (i = 0; i < Node->Entries; i++)
  1628.     {
  1629.       New.Entry[i] = NULL;
  1630.  
  1631.       project_bounding_slab(&Temp, &New.Entry[New.Entries], Node->Node[i]);
  1632.  
  1633.       /* Use only visible entries. */
  1634.  
  1635.       if (New.Entry[New.Entries] != NULL)
  1636.       {
  1637.         New.Project.x1 = min(New.Project.x1, Temp.x1);
  1638.         New.Project.x2 = max(New.Project.x2, Temp.x2);
  1639.         New.Project.y1 = min(New.Project.y1, Temp.y1);
  1640.         New.Project.y2 = max(New.Project.y2, Temp.y2);
  1641.  
  1642.         New.Entries++;
  1643.       }
  1644.     }
  1645.  
  1646.     /* If there are any visible entries, we'll use them. */
  1647.  
  1648.     if (New.Entries > 0)
  1649.     {
  1650.       /* If there's only one entry, we won't need a new node. */
  1651.  
  1652.       if (New.Entries == 1)
  1653.       {
  1654.         *Tree    = New.Entry[0];
  1655.         *Project = New.Project;
  1656.       }
  1657.       else
  1658.       {
  1659.         /* Allocate memory for new node in the vista tree. */
  1660.  
  1661.         *Tree = (PROJECT_TREE_NODE *)POV_MALLOC(sizeof(PROJECT_TREE_NODE), "vista tree node");
  1662.  
  1663.         **Tree = New;
  1664.  
  1665.         /* Allocate memory for node/leaf entries. */
  1666.  
  1667.         (*Tree)->Entry = (PROJECT_TREE_NODE **)POV_MALLOC(New.Entries*sizeof(PROJECT_TREE_NODE *), "vista tree node");
  1668.  
  1669.         memcpy((*Tree)->Entry, New.Entry, New.Entries*sizeof(PROJECT_TREE_NODE *));
  1670.  
  1671.         *Project = New.Project;
  1672.       }
  1673.     }
  1674.  
  1675.     /* Get rid of temporary node/leaf entries. */
  1676.  
  1677.     POV_FREE(New.Entry);
  1678.   }
  1679.   else
  1680.   {
  1681.     COOPERATE_0
  1682.  
  1683.     /* Current object is a normal object, i.e. a leaf in the slab tree. */
  1684.  
  1685.     /* Get object's projection. */
  1686.  
  1687.     project_object((OBJECT *)Node->Node, Project);
  1688.  
  1689.     /* Is the object visible? */
  1690.  
  1691.     if ((Project->x1 <= Project->x2) && (Project->y1 <= Project->y2))
  1692.     {
  1693.       /* Allocate memory for new leaf in the vista tree.  */
  1694.  
  1695.       *Tree = (PROJECT_TREE_NODE *)POV_MALLOC(sizeof(PROJECT_TREE_LEAF), "vista tree leaf");
  1696.  
  1697.       /* Init new leaf. */
  1698.  
  1699.       Leaf = (PROJECT_TREE_LEAF *)(*Tree);
  1700.  
  1701.       Leaf->Node = Node;
  1702.  
  1703.       Leaf->Project = *Project;
  1704.  
  1705.       /* Yes, this is a leaf. */
  1706.  
  1707.       Leaf->is_leaf = TRUE;
  1708.     }
  1709.   }
  1710. }
  1711.  
  1712.  
  1713.  
  1714. /*****************************************************************************
  1715. *
  1716. * FUNCTION
  1717. *
  1718. *   Build_Vista_Buffer
  1719. *
  1720. * INPUT
  1721. *   
  1722. * OUTPUT
  1723. *   
  1724. * RETURNS
  1725. *   
  1726. * AUTHOR
  1727. *
  1728. *   Dieter Bayer
  1729. *   
  1730. * DESCRIPTION
  1731. *
  1732. *   Build the vista tree, i.e. the 2d representation of the bounding slab
  1733. *   hierarchy in image space.
  1734. *
  1735. *   This only works for perspective and orthographic cameras.
  1736. *
  1737. * CHANGES
  1738. *
  1739. *   May 1994 : Creation.
  1740. *
  1741. ******************************************************************************/
  1742.  
  1743. void Build_Vista_Buffer()
  1744. {
  1745.   PROJECT Project;
  1746.  
  1747.   Root_Vista = NULL;
  1748.  
  1749.   /* Check if vista buffer can be used. */
  1750.  
  1751.   if ((!opts.Use_Slabs) ||
  1752.       (Frame.Camera->Tnormal != NULL) ||
  1753.       ((Frame.Camera->Type != PERSPECTIVE_CAMERA) && (Frame.Camera->Type != ORTHOGRAPHIC_CAMERA)) ||
  1754.       ((Frame.Camera->Aperture != 0.0) && (Frame.Camera->Blur_Samples > 0)))
  1755.   {
  1756.     opts.Options &= ~USE_VISTA_BUFFER;
  1757.   }
  1758.  
  1759.   if (opts.Options & USE_VISTA_BUFFER)
  1760.   {
  1761.     Status_Info("\nCreating vista buffer.");
  1762.  
  1763.     init_view_coordinates();
  1764.  
  1765.     project_bounding_slab(&Project, &Root_Vista, Root_Object);
  1766.   }
  1767. }
  1768.  
  1769.  
  1770.  
  1771. /*****************************************************************************
  1772. *
  1773. * FUNCTION
  1774. *
  1775. *   Destroy_Vista_Buffer
  1776. *
  1777. * INPUT
  1778. *   
  1779. * OUTPUT
  1780. *   
  1781. * RETURNS
  1782. *   
  1783. * AUTHOR
  1784. *
  1785. *   Dieter Bayer
  1786. *   
  1787. * DESCRIPTION
  1788. *
  1789. *   Destroy the vista tree.
  1790. *
  1791. * CHANGES
  1792. *
  1793. *   Sep 1994 : Creation.
  1794. *
  1795. ******************************************************************************/
  1796.  
  1797. void Destroy_Vista_Buffer()
  1798. {
  1799.   if ((opts.Options & USE_VISTA_BUFFER) && (Root_Vista != NULL))
  1800.   {
  1801.     Destroy_Project_Tree(Root_Vista);
  1802.  
  1803.     Root_Vista = NULL;
  1804.   }
  1805. }
  1806.  
  1807.  
  1808.  
  1809. /*****************************************************************************
  1810. *
  1811. * FUNCTION
  1812. *
  1813. *   draw_projection
  1814. *
  1815. * INPUT
  1816. *
  1817. *   Project - projection to draw
  1818. *   color   - Color to be used
  1819. *   
  1820. * OUTPUT
  1821. *   
  1822. * RETURNS
  1823. *   
  1824. * AUTHOR
  1825. *
  1826. *   Dieter Bayer
  1827. *   
  1828. * DESCRIPTION
  1829. *
  1830. *   Draws a projection in the specified color.
  1831. *
  1832. * CHANGES
  1833. *
  1834. *   May 1994 : Creation.
  1835. *   Jul 1996 : Draw boxes in white when doing grayscale preview
  1836. *
  1837. ******************************************************************************/
  1838.  
  1839. static void draw_projection(Project, color, BigRed, BigBlue)
  1840. PROJECT *Project;
  1841. int color, *BigRed, *BigBlue;
  1842. {
  1843.   int x1, x2, y1, y2, draw_it;
  1844.   unsigned char r, g, b, gray;
  1845.   unsigned char a=255;
  1846.  
  1847.   gray = (opts.PaletteOption == GREY) ? 255 : 0;
  1848.  
  1849.   switch (color)
  1850.   {
  1851.     case RED   : r = 255; g = b = gray; break;
  1852.     case GREEN : g = 255; r = b = gray; break;
  1853.     case BLUE  : b = 255; r = g = gray; break;
  1854.     default    : r = g = b = 255;
  1855.   }
  1856.  
  1857.   x1 = Project->x1;
  1858.   x2 = Project->x2;
  1859.   y1 = Project->y1;
  1860.   y2 = Project->y2;
  1861.  
  1862.   if ((x1 <= x2) && (y1 <= y2))
  1863.   {
  1864.     if (x1 < 0) x1 = 0;
  1865.     if (x2 < 0) x2 = 0;
  1866.     if (y1 < 0) y1 = 0;
  1867.     if (y2 < 0) y2 = 0;
  1868.  
  1869.     if (x1 >= Frame.Screen_Width)  x1 = Frame.Screen_Width - 1;
  1870.     if (x2 >= Frame.Screen_Width)  x2 = Frame.Screen_Width - 1;
  1871.     if (y1 >= Frame.Screen_Height) y1 = Frame.Screen_Height - 1;
  1872.     if (y2 >= Frame.Screen_Height) y2 = Frame.Screen_Height - 1;
  1873.  
  1874.     /* Check for full-screen rectangle. */
  1875.  
  1876.     draw_it = TRUE;
  1877.  
  1878.     if ((x1 == 0) && (x2 == Frame.Screen_Width - 1) &&
  1879.         (y1 == 0) && (y2 == Frame.Screen_Height - 1))
  1880.     {
  1881.       draw_it = FALSE;
  1882.  
  1883.       switch (color)
  1884.       {
  1885.         case RED   : if (!(*BigRed))  { *BigRed  = draw_it = TRUE; } break;
  1886.         case BLUE  : if (!(*BigBlue)) { *BigBlue = draw_it = TRUE; } break;
  1887.       }
  1888.     }
  1889.  
  1890.     if (draw_it)
  1891.     {
  1892.       POV_DISPLAY_PLOT_BOX(x1,y1,x2,y2,r,g,b,a);
  1893.     }
  1894.   }
  1895. }
  1896.  
  1897.  
  1898.  
  1899. /*****************************************************************************
  1900. *
  1901. * FUNCTION
  1902. *
  1903. *   draw_vista
  1904. *
  1905. * INPUT
  1906. *
  1907. *   Tree - current node/leaf in the vista tree
  1908. *   
  1909. * OUTPUT
  1910. *   
  1911. * RETURNS
  1912. *   
  1913. * AUTHOR
  1914. *
  1915. *   Dieter Bayer
  1916. *   
  1917. * DESCRIPTION
  1918. *
  1919. *   Draws recursively all projections of subnodes in the current node.
  1920. *
  1921. * CHANGES
  1922. *
  1923. *   May 1994 : Creation.
  1924. *
  1925. ******************************************************************************/
  1926.  
  1927. static void draw_vista(Tree, BigRed, BigBlue)
  1928. PROJECT_TREE_NODE *Tree;
  1929. int *BigBlue, *BigRed;
  1930. {
  1931.   unsigned short i;
  1932.   PROJECT_TREE_LEAF *Leaf;
  1933.  
  1934.   if (Tree->is_leaf)
  1935.   {
  1936.     Leaf = (PROJECT_TREE_LEAF *)Tree;
  1937.  
  1938.     COOPERATE_1
  1939.  
  1940.     if (((OBJECT *)Leaf->Node->Node)->Type & COMPOUND_OBJECT)
  1941.     {
  1942.       draw_projection(&Leaf->Project, BLUE, BigRed, BigBlue);
  1943.     }
  1944.     else
  1945.     {
  1946.       draw_projection(&Leaf->Project, RED, BigRed, BigBlue);
  1947.     }
  1948.   }
  1949.   else
  1950.   {
  1951.     for (i = 0; i < Tree->Entries; i++)
  1952.     {
  1953.       draw_vista(Tree->Entry[i], BigRed, BigBlue);
  1954.     }
  1955.   }
  1956.  
  1957.   /* draw bounding object's vista */
  1958.  
  1959. /*
  1960.   draw_projection(&Tree->Project, GREEN);
  1961. */
  1962. }
  1963.  
  1964.  
  1965.  
  1966. /*****************************************************************************
  1967. *
  1968. * FUNCTION
  1969. *
  1970. *   Draw_Vista_Buffer
  1971. *
  1972. * INPUT
  1973. *   
  1974. * OUTPUT
  1975. *   
  1976. * RETURNS
  1977. *   
  1978. * AUTHOR
  1979. *
  1980. *   Dieter Bayer
  1981. *   
  1982. * DESCRIPTION
  1983. *
  1984. *   Draw the vista tree.
  1985. *
  1986. * CHANGES
  1987. *
  1988. *   May 1994 : Creation.
  1989. *
  1990. ******************************************************************************/
  1991.  
  1992. void Draw_Vista_Buffer()
  1993. {
  1994.   int BigRed, BigBlue;
  1995.  
  1996.   BigRed = BigBlue = FALSE;
  1997.  
  1998.   if ((Root_Vista != NULL) && (opts.Options & USE_VISTA_DRAW))
  1999.   {
  2000.     draw_vista(Root_Vista, &BigRed, &BigBlue);
  2001.   }
  2002. }
  2003.  
  2004. /*****************************************************************************
  2005. *
  2006. * FUNCTION
  2007. *
  2008. *   POV_Std_Display_Plot_Box
  2009. *
  2010. * INPUT
  2011. *   
  2012. * OUTPUT
  2013. *   
  2014. * RETURNS
  2015. *   
  2016. * AUTHOR
  2017. *
  2018. *   Chris Young
  2019. *   
  2020. * DESCRIPTION
  2021. *
  2022. *   Generic box drawing routine which may be overriden in POV_DRAW_BOX
  2023. *   by a platform specific routine.
  2024. *
  2025. * CHANGES
  2026. *
  2027. *   Nov 1995 : Creation.
  2028. *
  2029. ******************************************************************************/
  2030. static void POV_Std_Display_Plot_Box(x1,y1,x2,y2,r,g,b,a)
  2031.   int x1,y1,x2,y2;
  2032.   unsigned int r,g,b,a;
  2033.   {
  2034.      int x,y;
  2035.    
  2036.      for (x = x1; x <= x2; x++)
  2037.      {
  2038.        POV_DISPLAY_PLOT(x, y1, r, g, b, a);
  2039.        POV_DISPLAY_PLOT(x, y2, r, g, b, a);
  2040.      }
  2041.  
  2042.      for (y = y1; y <= y2; y++)
  2043.      {
  2044.        POV_DISPLAY_PLOT(x1, y, r, g, b, a);
  2045.        POV_DISPLAY_PLOT(x2, y, r, g, b, a);
  2046.      }
  2047.   }
  2048.